// 四、手写实现MyPromise源码

/*
    1.Promise是一个类 执行类的时候 需要传一个执行器，执行器会立即执行
    2.Promise 中有三种状态 分别为 成功 fulfilled 失败 rejected 等待 pending
        pending -> fulfuilled
        pending -> rejected
        一旦状态确定就不可改
    3.resolve和reject函数是用来更改状态的
        resolve:fuilled
        reject:rejected
    4.then方法内部要做的事情就是判断状态，如果状态是成功调用成功的回调函数，失败则失败回调函数
    5.then成功回调有一个参数，表示成功后的值，then失败有一个参数，表示失败的原因
    6.then中需判断上一步非成功也非失败的情况，即异步回调的执行。
        这时先将then中的成功回调和失败回调存储，然后在resolve和reject中去判断执行
    7.多次调用then且是异步的时候，将所有then中的回调函数用数组存储起来，然后在resolve和reject中去判断执行
    8.then可以链式调用，所以then要返回Promise对象。上一个then的返回值，要传递给下一个then，所以要用resolve。
        如果返回值是一个Promise对象，需要去判断返回结果，成功resolve，失败reject
    9.then不能return自身promise，所以要去判断。如果错误则new TypeError
    10.捕获错误
    11.then可选参数，成功回调不存在则默认参数为 value=>value，失败回调不存在 则reason => { throw reason }
    12.静态all，接收并返回数组。数组中每一项，如果有Promise对象，则调用then方法，执行成功或失败
        定义一个计数变量 index，用来记录数组，index等于数组长度时，调用resolve返回数组
    13.静态resolve，返回promise。如果参数是promise，则返回。如果是普通值，则转成promise
    14.finally参数为回调函数。调用then函数，去执行finally的回调函数。
        返回promise，并return value或throw reason
        异步：调用静态resolve将callback转成promise，然后在then执行
    15.catch this.then(undefined, failCallback) 即可
    16.静态reject，返回promise。如果参数是promise，则返回。如果是普通值，则转成promise
    17.静态race,赛跑，先结束的返回
*/



const PENDING = 'pending';//等待
const FULFILLED = 'fulfilled';//成功
const REJECTED = 'rejected';//失败

class MyPromise {
    //状态默认等待
    static = PENDING;
    //失败的值
    reason = undefined;
    //成功的值
    value = undefined;
    //成功回调
    successCallback = [];
    //失败回调
    failCallback = [];
    constructor(executor) {
        try {//捕获错误
            executor(resolve, reject)
        } catch (e) {
            this.reject(e)
        }
    }
    resolve = value => {//箭头函数，this指向Promise
        //状态不可变
        if (this.static !== PENDING) return;
        //状态改为成功
        this.static = FULFILLED;
        //将成功的值，存储
        this.value = value
        //判断成功回调是否存在，存在即调用
        // this.successCallback && this.successCallback(this.value)
        while (this.successCallback.length) this.successCallback.shift()()
    }
    reject = reason => {
        //状态不可变
        if (this.static !== PENDING) return;
        //状态改为失败
        this.static = REJECTED;
        //将失败的值，存储
        this.reason = reason
        //判断失败回调是否存在，存在即调用
        // this.failCallback && this.failCallback(this.reason)
        while (this.failCallback.length) this.failCallback.shift()()
    }
    then(successCallback, failCallback) {
        // 参数可选
        successCallback = successCallback ? successCallback : value => value;
        // 参数可选
        failCallback = failCallback ? failCallback : reason => { throw reason };

        let promise2 = new MyPromise((resolve, reject) => {
            if (this.static === FULFILLED) {
                setTimeout(() => {//变成异步代码，用于获取promise2
                    try {//捕获错误
                        let x = successCallback(this.value)//成功回调
                        // resolve(x)//传递给下一个then
                        //判读x是不是promise对象
                        //如果不是直接调用 resolve
                        //如果是，查看promise返回结果，并决定调用resolve还是reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else if (this.static === REJECTED) {
                setTimeout(() => {//变成异步代码，用于获取promise2
                    try {//捕获错误
                        let x = failCallback(this.reason)//失败回调
                        // resolve(x)//传递给下一个then
                        //判读x是不是promise对象
                        //如果不是直接调用 resolve
                        //如果是，查看promise返回结果，并决定调用resolve还是reject
                        resolvePromise(promise2, x, resolve, reject)
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            } else {
                //异步等待
                //将成功回调和失败回调都存储起来，暂不调用
                this.successCallback.push(() => {
                    setTimeout(() => {//变成异步代码，用于获取promise2
                        try {//捕获错误
                            let x = successCallback(this.value)//成功回调
                            // resolve(x)//传递给下一个then
                            //判读x是不是promise对象
                            //如果不是直接调用 resolve
                            //如果是，查看promise返回结果，并决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
                this.failCallback.push(() => {
                    setTimeout(() => {//变成异步代码，用于获取promise2
                        try {//捕获错误
                            let x = failCallback(this.reason)//失败回调
                            // resolve(x)//传递给下一个then
                            //判读x是不是promise对象
                            //如果不是直接调用 resolve
                            //如果是，查看promise返回结果，并决定调用resolve还是reject
                            resolvePromise(promise2, x, resolve, reject)
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
            }
        })

        //实现then的链式调用
        return promise2
    }
    finally(callback) {
        //返回promise对象
        return this.then(value => {
            //执行callback()，兼容异步函数
            //即：将callback传入resolve
            return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }
    //全局捕获，调用failCallback
    catch(failCallback) {
        return this.then(undefined, failCallback)
    }
    static all(array) {
        let result = [];
        let index = 0;//监听array个数
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;//将值存入数组
                index++;
                if (index === array.length) {
                    resolve(result);//数量正确时，返回
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // promise 对象
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }
    //将值转化为promise对象，并返回
    static resolve(value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }
    //reject
    static reject(reason) {
        if (reason instanceof MyPromise) return reason;
        return new MyPromise((resolve, reject) => reject(reason));
    }
    //race
    static race(array) {
        return new MyPromise((resolve, reject) => {
          function addData (value) {
              resolve(value);
          }
          for (let i = 0; i < array.length; i++) {
            let current = array[i];
            if (current instanceof MyPromise) {
              // promise 对象
              current.then(value => addData(value), reason => reject(reason))
            }else {
              // 普通值
              addData(array[i]);
            }
          }
        })
    }
}

function resolvePromise(promise2, x, resolve, reject) {
    //调用不能返回自身
    if (promise2 === x) {
        return reject(new TypeError('返回了自身'))
    }
    if (x instanceof MyPromise) {
        //promise对象
        x.then(resolve, reject)
    } else {
        //普通值
        resolve(x)
    }
}

module.exports = MyPromise;